package com.example.alibabanacosdiscoveryclient01.controller;

import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.example.alibabanacosdiscoveryclient01.entity.ActorsFilms;
import com.example.alibabanacosdiscoveryclient01.service.MockOrderService;
import com.example.alibabanacosdiscoveryclient01.service.impl.MockOrderServiceImpl;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.Generation;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.converter.BeanOutputConverter;
import org.springframework.ai.converter.ListOutputConverter;
import org.springframework.ai.converter.MapOutputConverter;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.ai.model.function.FunctionCallback;
//import org.springframework.ai.model.function.FunctionCallbackWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author:guoq
 * @date:2025/1/16
 * @descripion:
 */
@RestController
@RequestMapping("/ai")
@Tag(name = "嵌入模型、FullCalling、Struct")
public class EmbedFullCallStructController {

    @Autowired
    EmbeddingModel embeddingModel;
    @Autowired
    MockOrderService mockOrderService;
    @Autowired
    private ChatModel chatModel;
    private final ChatClient chatClient;
    public EmbedFullCallStructController(ChatClient.Builder chatClient) {
        this.chatClient = chatClient.build();
    }
    @GetMapping("/embedding")
    @Operation(summary = "嵌入模型简单调用")
    public float[] embed(@RequestParam(value = "message") String message) {
        float[] floats = this.embeddingModel.embed(message);
        return floats;
    }

    @GetMapping("/embedForResponse")
    @Operation(summary = "嵌入模型返回元数据")
    public Map embedForResponse(@RequestParam(value = "message1") String message, @RequestParam(value = "message2") String message2) {
        List<String> list = Arrays.asList(message, message2);
        EmbeddingResponse embeddingResponse = this.embeddingModel.embedForResponse(list);
        int dimensions = this.embeddingModel.dimensions();
        return Map.of("dimesion", dimensions, "embedding", embeddingResponse);
    }

    @GetMapping("/functionCalling")
    @Operation(summary = "functionCall声明式调用")
    public String functionCalling(@RequestParam String orderCode, @RequestParam String userCode) {
        ChatResponse orderFunction = chatClient.prompt()
                .functions("orderFunction")
                .user("帮我一下订单, 订单编号" + orderCode + "用户编号为:" + userCode)
                .call()
                .chatResponse();
//        return orderFunction.getResult().getOutput().getContent();
        return orderFunction.getResult().getOutput().getText();
    }

    @GetMapping("/functionCalling-dynamic")
    @Operation(summary = "functionCall动态注册")
    public String functionCallingDynamic(@RequestParam String orderCode, @RequestParam String userCode) {
        //动态注册function
//        FunctionCallbackWrapper wrapper = FunctionCallbackWrapper.builder(new MockOrderServiceImpl())
//                .withName("orderFunction")
//                .withDescription("get a order")
//                .build();
        FunctionCallback wrapper = FunctionCallback.builder()
                .method("mockOrder", MockOrderServiceImpl.Request.class)
                .targetObject(mockOrderService)
                .name("orderFunction")
                .description("get a order")
                .build();
        //设置聊天的option
        DashScopeChatOptions build = DashScopeChatOptions.builder()
                .withFunctionCallbacks(List.of(wrapper)
                ).build();
        //调用聊天，实现下单
        ChatResponse orderFunction = chatClient.prompt()
                .user("帮我一下订单, 订单编号" + orderCode + "用户编号为:" + userCode)
                .options(build)
                .call()
                .chatResponse();

//        return orderFunction.getResult().getOutput().getContent();
        return orderFunction.getResult().getOutput().getText();
    }
    @GetMapping("/structToBeanByChatClient")
    @Operation(summary = "结构化成实体类(ChatClient)")
    public ActorsFilms structToBeanByChatClient(String actor) {
        ActorsFilms actorsFilms = chatClient.prompt()
                .user(u -> u.text("列举5部关于{actor}的电影名")
                        .param("actor", actor))
                .call()
                .entity(ActorsFilms.class);
        return  actorsFilms;
    }
    @GetMapping("/structToMapByChatClient")
    @Operation(summary = "结构化成Map(ChatClient)")
    public Map structToMapByChatClient(String actor) {
        Map<String, Object> result = chatClient.prompt()
                .user(u -> u.text("列举5部关于{actor}的电影名,key叫name")
                        .param("actor", actor))
                .call()
                .entity(new MapOutputConverter());
        return  result;
    }
    @GetMapping("/structToListByChatClient")
    @Operation(summary = "结构化成List(ChatClient)")
    public List structToListByChatClient(String actor) {
        List<String> result = ChatClient.create(chatModel).prompt()
                .user(u -> u.text("列举5部关于{actor}的电影名")
                        .param("actor", actor))
                .call()
                .entity(new ListOutputConverter(new DefaultConversionService()));
        return  result;
    }
    @GetMapping("/structToBeanByChatModel")
    @Operation(summary = "结构化成实体类(ChatModel)")
    public ActorsFilms structToBeanByChatModel(String actor) {
        BeanOutputConverter<ActorsFilms> beanOutputConverter = new BeanOutputConverter(ActorsFilms.class);
        //获取format
        String format =beanOutputConverter.getFormat();
        String template = """
        列举5部关于{actor}的电影名.
        {format}
        """;
        //组装prompt
        Prompt prompt = new PromptTemplate(template, Map.of("actor", actor, "format", format))
                .create();
        //调用模型
        Generation generation = chatModel.call(prompt)
                .getResult();
        //解析结构化数据
//        ActorsFilms actorsFilms = beanOutputConverter.convert(generation.getOutput().getContent());
        ActorsFilms actorsFilms = beanOutputConverter.convert(generation.getOutput().getText());
        return  actorsFilms;
    }
    @GetMapping("/structToMapByChatModel")
    @Operation(summary = "结构化成Map(ChatModel)")
    public Map structToMapByChatModel(String actor) {
        MapOutputConverter mapOutputConverter = new MapOutputConverter();
        //获取format
        String format =mapOutputConverter.getFormat();
        String template = """
       列举5部关于{actor}的电影名,key叫name.
        {format}
        """;
        //组装prompt
        Prompt prompt = new PromptTemplate(template, Map.of("actor", actor, "format", format))
                .create();
        //调用模型
        Generation generation = chatModel.call(prompt)
                .getResult();
        //解析结构化数据
//        Map<String, Object> result = mapOutputConverter.convert(generation.getOutput().getContent());
        Map<String, Object> result = mapOutputConverter.convert(generation.getOutput().getText());
        return  result;
    }
    @GetMapping("/structToListByChatModel")
    @Operation(summary = "结构化成List(ChatModel)")
    public List structToListByChatModel(String actor) {
        ListOutputConverter listOutputConverter = new ListOutputConverter(new DefaultConversionService());
        //获取format
        String format =listOutputConverter.getFormat();
        String template = """
        列举5部关于{actor}的电影名.
        {format}
        """;
        //组装prompt
        Prompt prompt = new PromptTemplate(template, Map.of("actor", actor, "format", format))
                .create();
        //调用模型
        Generation generation = chatModel.call(prompt)
                .getResult();
        //解析结构化数据
//        List<String> result = listOutputConverter.convert(generation.getOutput().getContent());
        List<String> result = listOutputConverter.convert(generation.getOutput().getText());
        return  result;
    }
    @GetMapping("/structToListByChatClientByParamTypeRef")
    @Operation(summary = "结构化成List使用ParamTypeRef(ChatClient)")
    public List structToListByChatClientByParamTypeRef(String actor,String actor2) {
        List<ActorsFilms> result = chatClient.prompt()
                .user(u -> u.text("列举5部关于{actor}和{actor2}的电影名")
                        .params(Map.of("actor", actor, "actor2", actor2)))
                .call()
                .entity(new ParameterizedTypeReference<List<ActorsFilms>>() {
                });
        return result;
    }
    @GetMapping("/structToListByChatModelByParamTypeRef")
    @Operation(summary = "结构化成List使用ParamTypeRef(ChatModel)")
    public List structToListByChatModelByParamTypeRef(String actor,String actor2) {
        BeanOutputConverter<List<ActorsFilms>> outputConverter = new BeanOutputConverter<>(
                new ParameterizedTypeReference<List<ActorsFilms>>() { });        //获取format
        String format =outputConverter.getFormat();
        String template = """
        列举5部关于{actor}和{actor2}的电影名.
        {format}
        """;
        //组装prompt
        Prompt prompt = new PromptTemplate(template, Map.of("actor", actor, "actor2",actor2,"format", format))
                .create();
        //调用模型
        Generation generation = chatModel.call(prompt)
                .getResult();
        //解析结构化数据
//        List<ActorsFilms> result = outputConverter.convert(generation.getOutput().getContent());
        List<ActorsFilms> result = outputConverter.convert(generation.getOutput().getText());
        return  result;
    }
}
